package com.sxhuayuan.parking.queue.rabbitmq.consumer;

import java.io.IOException;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.rabbitmq.client.Channel;
import com.sxhuayuan.parking.compenent.RabbitMQConfig;
import com.sxhuayuan.parking.config.PartnerpayScene;
import com.sxhuayuan.parking.config.PayStatus;
import com.sxhuayuan.parking.config.Platform;
import com.sxhuayuan.parking.entity.OemConfig;
import com.sxhuayuan.parking.entity.Order;
import com.sxhuayuan.parking.entity.ParkingIn;
import com.sxhuayuan.parking.entity.ParkingLot;
import com.sxhuayuan.parking.entity.Partnerpay;
import com.sxhuayuan.parking.plugin.partnerpay.PartnerpayApiService;
import com.sxhuayuan.parking.plugin.partnerpay.req.PayApplyReq;
import com.sxhuayuan.parking.plugin.partnerpay.result.PayApplyResult;
import com.sxhuayuan.parking.queue.msg.PartnerpayQueueMsg;
import com.sxhuayuan.parking.queue.msg.QueueMsg;
import com.sxhuayuan.parking.service.OemConfigService;
import com.sxhuayuan.parking.service.OrderService;
import com.sxhuayuan.parking.service.ParkingInOutService;
import com.sxhuayuan.parking.service.ParkingInService;
import com.sxhuayuan.parking.service.ParkingLotService;
import com.sxhuayuan.parking.service.PartnerpayLogService;
import com.sxhuayuan.parking.service.PartnerpayService;
import com.sxhuayuan.parking.service.PluginService;
import com.sxhuayuan.parking.utils.DateUtils;
import com.sxhuayuan.parking.utils.SettingUtils;

@Component("partnerpayConsumer")
@RabbitListener(queues = RabbitMQConfig.QUEUE_DELAY_PARTNERPAY)
public class PartnerpayConsumer {

	Logger log = LoggerFactory.getLogger(getClass());

	@Resource(name = "pluginServiceImpl")
	PluginService pluginService;
	@Resource(name = "parkingLotServiceImpl")
	ParkingLotService lotService;
	@Resource(name = "parkingInServiceImpl")
	ParkingInService inService;
	@Resource(name = "parkingInOutServiceImpl")
	ParkingInOutService parkingInOutService;
	@Resource(name = "partnerpayServiceImpl")
	PartnerpayService partnerpayService;
	@Resource(name = "orderServiceImpl")
	OrderService orderService;
	@Resource(name = "partnerpayLogServiceImpl")
	PartnerpayLogService partnerpayLogService;
	@Resource(name = "oemConfigServiceImpl")
	OemConfigService oemConfigService;

	/**
	 * 处理消息
	 * 
	 * 微信需要先查询车牌和appid之间的授权关系，没错，每个服务商都需要用户授权一次才可以
	 * 
	 * 支付宝
	 * 
	 * @param msg
	 * @throws IOException
	 */
	@RabbitHandler
	private void handlerMsg(byte[] bytes, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {
		try {
			QueueMsg msg = JSON.parseObject(bytes, QueueMsg.class);
			PartnerpayQueueMsg body = JSON.parseObject(msg.getBody(), PartnerpayQueueMsg.class);
			log.debug("[{}]无感扣费开始", msg.getId(), body.getCarPlate());

			ParkingIn in = inService.findByUniqueId(msg.getId());
			if (in == null) {
				log.error("[{}]未找到入场记录", msg.getId());
				channel.basicAck(tag, false);
				return;
			}

			Platform platform = in.getPlatform();

			// 调用入场接口通知平台
			PartnerpayApiService partnerpayApiService = pluginService.getPartnerpayApiService(platform);
			if (partnerpayApiService == null) {
				log.error("[{}]partnerpayApiService is null!");
				channel.basicNack(tag, false, false);
				return;
			}

			Order order = null;
			if (!StringUtils.isEmpty(body.getOrderSn())) {
				order = orderService.findBySn(body.getOrderSn());
			}
			ParkingLot lot = lotService.findById(in.getParkingLotId());
			// if (order == null) {
			// // why?
			// Date endTime = DateUtils.parse(body.getOutTime(), DateUtils.YYYYMMDDHHMMSS);
			// String ip = DeviceUtil.getInternetIp();
			// ParkFeeCacheBean parkFee = new ParkFeeCacheBean();
			// parkFee.setDiscountFee(null);
			// parkFee.setEndTime(endTime);
			// parkFee.setExitId(body.getExitId());
			// parkFee.setParkPluginId(lot.getPluginId());
			// parkFee.setTotalFee(body.getFee());
			// parkFee.setUniqueId(in.getUniqueId());
			// order = orderService.create(in, parkFee, null, platform, PayMode.partnerpay,
			// Order.Method.partnerpay, ip, "");
			// }
			OemConfig oem = oemConfigService.findByParkingLot(in.getParkingLotId());
			PayApplyReq req = new PayApplyReq();
			req.setAppid(oem.getWxAppid());
			req.setMchid(oem.getWxMchid());
			req.setSubAppid(oem.getWxSubAppid());
			req.setSubMchid(oem.getWxSubMchid());
			req.setMchKey(oem.getWxMchKey());
			req.setAttach(String.valueOf(in.getUniqueId()));
			req.setMoney(SettingUtils.get().setScale(order.getMoney()).floatValue());
			req.setOrderNo(order.getSn());
			req.setScene(PartnerpayScene.PARKING);
			Map<String, String> sceneInfo = new HashMap<>();
			sceneInfo.put("start_time", DateUtils.format(order.getStarttime(), DateUtils.YYYYMMDDHHMMSS));
			sceneInfo.put("end_time", DateUtils.format(order.getEndtime(), DateUtils.YYYYMMDDHHMMSS));
			long seconds = DateUtils.diff(order.getStarttime(), order.getEndtime(), Calendar.SECOND);
			sceneInfo.put("charging_time", String.valueOf(seconds));
			sceneInfo.put("plate_number", order.getCarPlate());
			sceneInfo.put("parking_name", lot.getName());
			req.setData(sceneInfo);
			PayApplyResult payApplyResult = partnerpayApiService.payApply(req);
			if (payApplyResult != null) {
				if (payApplyResult.getIsResultSuccess()) {
					order.setPayStatus(PayStatus.process);
					order.setIsRiseSuccess(true);
					orderService.update(order);
					log.debug("[{}]更新订单", msg.getId());
					try {
						parkingInOutService.out(in, order.getEndtime(), body.getExitId());
						log.debug("[{}]保存出场记录", msg.getId());
					} catch (Exception e) {
						log.error("", e);
					}
					partnerpayLogService.saveLog(order.getId(), order.getSn(), order.getCarPlate(), "SUCCESS", null);
					log.debug("[{}]保存日志", msg.getId());
					channel.basicAck(tag, false);
				} else {
					order.setPayStatus(PayStatus.fail);
					orderService.update(order);
					log.debug("[{}]扣款失败: {}, msg={}", msg.getId(), in.getCarPlate(), payApplyResult.getMsg());
					partnerpayLogService.saveLog(order.getId(), order.getSn(), order.getCarPlate(), payApplyResult.getErrcode(), payApplyResult.getMsg());

					// 根据结果决定是否需要进一步处理
					if (payApplyResult.isUserOverdue()) {
						// 添加提醒用户欠费模板消息任务
						log.debug("[{}]用户欠费:{}", msg.getId(), order.getCarPlate());
					} else if (payApplyResult.isUserBlocked()) {
						Partnerpay partner = partnerpayService.findByCarPlateAndPlatform(in.getCarPlate(), platform);
						if (partner == null) {
							partner = new Partnerpay();
							partner.setPlatform(platform);
							// partner.setMember(member);
							partner.setCarPlate(body.getCarPlate());
						}
						partner.setState(Partnerpay.State.BLOCKED);
						partnerpayService.update(partner);
						log.debug("[{}]用户状态不可用:{}", msg.getId(), order.getCarPlate());
						// 添加提醒用户欠费模板消息任务
					}
					channel.basicNack(tag, false, false);
				}
			} else {
				String errmsg = "网络中断，结果未知";
				log.debug("[{}]调用入场api失败: {}, msg={}", msg.getId(), in.getCarPlate(), errmsg);
				partnerpayLogService.saveLog(order.getId(), order.getSn(), order.getCarPlate(), "FAIL", errmsg);
			}
		} catch (Exception e) {
			log.error("扣费失败", e);
			channel.basicAck(tag, false);
		}
	}
}
